package com.gitee.itembucket

import com.gitee.itembucket.core.bucket.Bucket
import com.gitee.itembucket.core.bucket.Size
import com.gitee.itembucket.core.storage.Storage
import org.bukkit.Bukkit
import org.bukkit.OfflinePlayer
import org.bukkit.entity.Player
import org.bukkit.event.player.PlayerQuitEvent
import taboolib.common.platform.Plugin
import taboolib.common.platform.event.SubscribeEvent
import taboolib.common.platform.function.info
import taboolib.common.platform.function.submitAsync
import taboolib.common5.Coerce
import taboolib.module.configuration.Config
import taboolib.module.configuration.Configuration
import taboolib.module.nms.getName
import taboolib.platform.BukkitPlugin
import java.util.concurrent.CompletableFuture

object ItemBucket : Plugin() {

    @Config
    lateinit var config: Configuration

    val maps = mutableMapOf<Player, Bucket>()

    val sizes = mutableListOf<Size>()

    val defaultSize: Size
        get() = sizes.firstOrNull { it.permission == "default" } ?: error("Size the lack of 'default'")

    val stackSize: Long
        get() = config.getLong("stack-size", 999)

    val isLogEnable: Boolean
        get() = config.getBoolean("database.log",false)

    val logTable : String
        get() = config.getString("database.log-table","item_bucket_log")!!

    val isBackpackFullGetEnable: Boolean
        get() = config.getBoolean("backpack-full-get.enable",false)

    val backpackFullGetRadius: Double
        get() = config.getDouble("backpack-full-get.radius",1.0)

    val column: Int
        get() = config.getInt("column",9)

    override fun onEnable() {
        Bukkit.getPluginManager().registerEvents(ListenerProxy(),BukkitPlugin.getInstance())
        sizes.clear()
        config.getMapList("size").forEach { map ->
            sizes += Size(
                map["permission"]!!.toString(),
                Coerce.toInteger(map["amount"])
            )
        }
    }

    fun getSize(player: Player): Size {
        return sizes.firstOrNull { it.permission != "default" && player.hasPermission(it.permission) } ?: defaultSize
    }

    fun getSize(bucket: Bucket): Size {

        // 模余求整数
        var amount = bucket.items.size / column
        if (column % bucket.items.size != 0) {
            amount++
        }


        return Size("off-online",amount)
    }

    fun divide(num1: Int,num2: Int): Int {
        var result = num1 / num2
        if (num2 % num1 != 0) {
            result++
        }
        return result
    }

    fun getBucket(player: Player): CompletableFuture<Bucket> {
        val future = CompletableFuture<Bucket>()
        submitAsync {
            future.complete(maps.computeIfAbsent(player) { Storage.INSTANCE.getBucket(player) })
        }
        return future
    }

    fun getBucket(player: OfflinePlayer): CompletableFuture<Bucket> {
        return if (player.isOnline) {
            getBucket(player.player!!)
        } else {
            val future = CompletableFuture<Bucket>()
            submitAsync {
                future.complete(Storage.INSTANCE.getBucket(player))
            }
            future
        }

    }

    fun getBucket(player: Player, name: String): CompletableFuture<Bucket> {

        return getBucket(player).thenApply {
            return@thenApply if (name.isNotEmpty()) {
                val clone = Bucket.Clone()
                it.items.forEach {
                    if (it.stack.getName(player).contains(name)) {
                        clone.items += it
                    }
                }
                clone
            } else {
                it
            }

        }
    }

    fun updateItem(player: Player, item: Bucket.Item) {
        if (item.id == -1L) {
            submitAsync { Storage.INSTANCE.createItem(player, item) }
        } else if (item.changed) {
            submitAsync { Storage.INSTANCE.updateItem(player, item) }
        }
    }

    fun updateBucket(player: Player, bucket: Bucket) {
        bucket.items.forEach {
            updateItem(player, it)
        }
    }

    fun isOpenable(player: Player): CompletableFuture<Bucket?> {
        return getBucket(player).thenApply {
            if (it.items.all { it.id != -1L && !it.changed }) it else null
        }
    }

    @SubscribeEvent
    fun e(e: PlayerQuitEvent) {
        val bucket = maps.remove(e.player) ?: return
        updateBucket(e.player, bucket)
    }

    fun debug(text: String) {
        if (config.getBoolean("debug", false)) {
            info(text)
        }
    }

}

